﻿using LightCAD.MathLib;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Threading.Tasks;

namespace LightCAD.Three
{
    public static  class TypeUtils
    {
        public static float[] toFloat32Array(double[] darr)
        {
            var farr = new float[darr.Length];
            for (var i = 0; i < farr.Length; i++)
            {
                farr[i] = (float)darr[i];
            }
            return farr;
        }
        public static float[] toFloat32Array(ListEx<double> darr)
        {
            var farr = new float[darr.Length];
            for (var i = 0; i < farr.Length; i++)
            {
                farr[i] = (float)darr[i];
            }
            return farr;
        }
        public static bool arrayNeedsUint32(int[] array)
        {

            // assumes larger values usually on last

            for (var i = array.Length - 1; i >= 0; --i)
            {

                if (array[i] >= 65535) return true; // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565

            }

            return false;

        }
        public static double arrayMin(double[] array)
        {

            if (array.Length == 0) return double.PositiveInfinity;

            var min = array[0];

            for (int i = 1, l = array.Length; i < l; ++i)
            {

                if (array[i] < min) min = array[i];

            }

            return min;

        }

        public static double[] copyFloatArray(double[] src)
        {
            var dest = new double[src.Length];
            src.CopyTo(dest, 0);
            return dest;
        }
        public static int arrayMin(int[] array)
        {

            if (array.Length == 0) return int.MaxValue;

            var min = array[0];

            for (int i = 1, l = array.Length; i < l; ++i)
            {

                if (array[i] < min) min = array[i];

            }

            return min;

        }


        public static double arrayMax(double[] array)
        {

            if (array.Length == 0) return double.NegativeInfinity;

            var max = array[0];

            for (int i = 1, l = array.Length; i < l; ++i)
            {

                if (array[i] > max) max = array[i];

            }

            return max;

        }
        public static int arrayMax(int[] array)
        {

            if (array.Length == 0) return int.MinValue;

            var max = array[0];

            for (int i = 1, l = array.Length; i < l; ++i)
            {

                if (array[i] > max) max = array[i];

            }

            return max;

        }
        public static TVal get<TKey, TVal>(this Dictionary<TKey, TVal> dic, TKey key)
        {
            if (dic.TryGetValue(key, out var val))
                return val;
            else
                return default;
        }
        public static void set<TKey, TVal>(this Dictionary<TKey, TVal> dic, TKey key, TVal val)
        {
            dic[key] = val;
        }
        public static float parseFloat(string val) 
        {
            return float.Parse(val);
        }
        public static int parseInt(string val)
        {
            return int.Parse(val);
        }
        public static byte[] ToByteArr(this double[] vals,bool toSingle=true) 
        {
            var byteArr = new byte[vals.Length * 4];
            for (int i = 0; i < vals.Length; i++)
            {
                var varl = vals[i];
                var offset = i * 4;
                var subByteArr = toSingle ? BitConverter.GetBytes((float)varl) : BitConverter.GetBytes(varl);
                byteArr[offset] = subByteArr[0];
                byteArr[offset + 1] = subByteArr[1];
                byteArr[offset + 2] = subByteArr[2];
                byteArr[offset + 3] = subByteArr[3];
            }
            return byteArr;
        }

        public static void setTimeout(Action action, int ms)
        {
            Task.Delay(ms).ContinueWith((task) => action());
        }

        //public static object getJToken(JsonValue token)
        //{

        //    if (token.Type == JTokenType.Undefined || token.Type == JTokenType.Null)
        //        return null;

        //    else if (token.Type == JTokenType.Object)
        //    {
        //        var jobj = new JsObj<object>();
        //        foreach (var item in token as JObject)
        //        {
        //            jobj.Add(item.Key, getJToken(item.Value));
        //        }
        //        return jobj;
        //    }

        //    else if (token.Type == JTokenType.Array)
        //    {
        //        var arr = new JsArr<object>();
        //        foreach (var item in token as JArray)
        //        {
        //            arr.Add(getJToken(item));
        //        }
        //        return arr;
        //    }
        //    else if (token.Type == JTokenType.String)
        //        return (string)token;
        //    else if (token.Type == JTokenType.Integer)
        //        return (int)token;
        //    else if (token.Type == JTokenType.Float)
        //        return (double)token;
        //    else if (token.Type == JTokenType.Boolean)
        //        return (bool)token;
        //    else if (token.Type == JTokenType.Date)
        //        return (DateTime)token;
        //    else if (token.Type == JTokenType.Bytes)
        //        return (byte[])token;
        //    else
        //        return null;

        //}

        public static sbyte[] packNormal(IList<double> nArr, sbyte[] target=null)
        {
            var result = target?? new sbyte[nArr.Count];
            for (int i = 0; i < nArr.Count; i++)
            {
                var d = nArr[i];
                if (d == 0)
                    result[i] = 0;
                else if (d > 0)
                    result[i] = Convert.ToSByte((int)(d * 127));
                else
                    result[i] = Convert.ToSByte((int)(d * 128));
            }
            return result;
        }
        public static sbyte[] packNormal(Vector3 vec3, sbyte[] target ,int offset)
        {
            var result = target;
            pack(0+offset,vec3.X);
            pack(1+offset,vec3.Y);
            pack(2+offset,vec3.Z);
            void pack(int i,double d)
            {
                if (d == 0)
                    result[i] = 0;
                else if (d > 0)
                    result[i] = Convert.ToSByte((int)(d * 127));
                else
                    result[i] = Convert.ToSByte((int)(d * 128));
            }
            return result;
        }
        public static byte[] packUV(IList<double> uv)
        {
            var result = new byte[uv.Count];
            for (int i = 0; i < uv.Count; i++)
            {
                var d = uv[i];
                result[i] = Convert.ToByte((int)(d * 255));
            }
            return result;
        }
        public static float packColor(Color c) 
        {
            var a = 1;
            return (int)Math.Round(c.R * 63) * 262144 + (int)Math.Round(c.G * 63) * 4096 + (int)Math.Round(c.B * 63) * 64 + (int)Math.Round(a * 63.0);
        }
    }
}
